<?php

/**
 * Unibuy SDK
 * @author chenshubo
 * 新版本接口
 */
namespace App\Service\VendorClient\ShopubuyApi;
use App\Service\BaseService;
use App\Service\Code\Normal;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;

class ShopubuyApiClient extends BaseService
{    
    const SIGN_TYPE_RSA     = "RSA";
    const SIGN_TYPE_RSA2    = "RSA2";
    private $config = [];
    public $routers=[
          "queryGoodsList"=>"goods.query",
          "queryGoodsPrice"=>"price.query",
          "queryGoodsBrand"=>"brand.query",
          "queryGoodsClass"=>"category.query",
          "queryGoodsStock"=>"stock.query",
          "orderCreate"=>"order.save",
          "orderQuery"=>"order.query",
          "orderCancel"=>"order.cancel",
          "queryShopList"=>"shop.query"
    ];
    
    public function __construct( $apiBody = [] ) 
    {
        $this->config = $apiBody;
    }
    
    /**
     * 创建订单
     * @param array $params
     * @return mixed
     */
    public function createOrder( $param = [] )
    {
        $orderInfo          = $param['supplierOrder'];
        $goodsList          = $param['orderGoods'];
    
        //获取下单商品信息
        $palceOrderGoods = [];
        foreach ($goodsList as $item ) {
            $palceOrderGoods[] = [
                'skuNo'       => $item['supplier_skucode'],
                'quantity'    => $item['quantity'],
            ];
        }
        //组装推送上游数据
        $requestParam = [
            'channelNo'     => $this->config['channel_no'],
            'outNo'         => $orderInfo['supplier_dsn'],
            'orderMessage'  => $orderInfo['order_remark'],
            'receiverName'  => $orderInfo['receive_name'],
            'mobPhone'      => $orderInfo['recveive_phone'],
            'idCard'        => $orderInfo['buyer_idcard'],
            'provinceName'  => $orderInfo['province'],
            'cityName'      => $orderInfo['city'],
            'areaName'      => $orderInfo['district'],
            'address'       => $orderInfo['receive_address'],
            'goodsList'     => $palceOrderGoods,
        ];
        $data = [
            'method' => 'orderCreate',
            'data' => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 订单取消
     * @param array $params
     * @return mixed
     */
    public function orderCancel( $param = [] )
    {
        $orderInfo = $param['supplierOrder'];
        $requestParam = [
            'channelNo'     => $this->config['channel_no'],
            'cancelCause'   => "取消订单，不要了！",
            'outNo'         => $orderInfo['supplier_csn'],
        ];
        $data = [
            'method' => 'orderCancel',
            'data' => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 物流查询
     * @param array $params
     * @return mixed
     */
    public function queryOrderExpress( $param = [] )
    {
        if( empty($param['supplier_dsn']) ) {
            return Normal::returnCode(Normal::FAIL,"except param supplier_dsn");
        }
        //组装推送上游数据
        $requestParam = [
            'channelNo' => $this->config['channel_no'],
            'outNo'     => $param['supplier_dsn'],
        ];
        
        $data = [
            'method' => 'orderQuery',
            'data' => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 查询商品列表
     * @param array $params
     * @return mixed
     */
    public function queryGoodsList( $param = [] )
    {
        
        //组装推送上游数据
        $requestParam = [
            'startTime'     => isset($this->config["start_time"]) ? $this->config["start_time"] : date("Y-m-d H:i:s",time()),
            'endTime'       => isset($this->config["end_time"]) ? $this->config["end_time"] : date("Y-m-d H:i:s",time()),
            'channelNo'     => $this->config['channel_no'],
            'pageNo'        => $param['page'] ?? 1,
            'pageSize'      => $param['limit'] ?? 100,
            'isDel'         => 1,
        ];
        $data = [
            'method' => 'queryGoodsList',
            'data' => $requestParam,
        ];
        $res = $this->execute($data);
        if( $res['code'] != Normal::SUC ) {
            return $res;
        }
        
        $goodsList = $res['data']['list'];
        $goodsTotal = $res['data']['total'];
        if( empty($goodsList) ) {
            return Normal::returnCode(Normal::SUC,"暂无数据",[
                'total' => $goodsTotal,
                'list'  => $goodsList
            ]);
        }
        
        $skuNos         = array_column($goodsList,'skuNo');
        $resQueryStock  = $this->queryGoodsStockBySkuCodes($skuNos);
        $skuStockList   = array_column($resQueryStock['data']['list'],null,'skuNo');
        
        //组装库存
        $needGoodsList = [];
        foreach ($goodsList as & $item )
        {
            $item['quantity'] = $skuStockList[$item['skuNo']]['quantity'] ?? 0 ;
            $needGoodsList[] = $item;
            unset($item);
        }
        
        return Normal::returnCode(Normal::SUC,"获取成功",[
            'total' => $goodsTotal,
            'list'  => $needGoodsList
        ]);
    }
    
    /**
     * 查询商品分类
     * @param array $params
     * @return mixed
     */
    public function queryGoodsClass( $param = [] )
    {
        //组装推送上游数据
        $requestParam = [
            'categoryNo'    => ''
        ];
        $data = [
            'method' => 'queryGoodsClass',
            'data' => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 查询商品分类
     * @param array $params
     * @return mixed
     */
    public function queryGoodsStockBySkuCodes( $SkuCodes = [] )
    {
        //组装推送上游数据
        $requestParam = [
            'channelNo' => $this->config['channel_no'],
            'skuNos'    => $SkuCodes,
        ];
        $data = [
            'method' => 'queryGoodsStock',
            'data' => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 查询商品价格
     * @param array $params
     * @return mixed
     */
    public function queryGoodsPriceBySkuNos( array $skuNos )
    {
        //组装推送上游数据
        $requestParam = [
            'channelNo'     => $this->config['channel_no'],
            'isDel'         => 1,
            'skuNos'        => $skuNos
        ];
        $data = [
            'method'    => 'queryGoodsPrice',
            'data'      => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 查询店铺
     * @param array $params
     * @return mixed
     */
    public function queryShopList()
    {
        //组装推送上游数据
        $requestParam = [
            'channelNo'     => '',
        ];
        $data = [
            'method'    => 'queryShopList',
            'data'      => $requestParam,
        ];
        return $this->execute($data);
    }
    
    /**
     * 签名
     * @param array $param
     * @param string $method
     */
    public function sign( array $param = [] , string $method )
    {
        $data = [
            'app_id'        => $this->config['appid'],
            'method'        => $method,
            'version'       => '1.0',
            'charset'       => 'UTF-8',
            'sign_type'     => self::SIGN_TYPE_RSA2,
            'timestamp'     => date('Y-m-d H:i:s'),
            'biz_content'   => json_encode($param),
        ];
        $content    = self::getSignContent($data,'UTF-8','UTF-8');
        $signResult = self::rsaSign($content, $this->config['private_key'],$this->config['charset'],$this->config['sign_type']);
        if( $signResult['code'] != Normal::SUC ) {
            return $signResult;
        }
        $data['sign'] = $signResult['data']['sign'];
        return Normal::returnCode(Normal::SUC,"获取成功",$data);
    }
    
    public static function getSignContent($params, $postCharset, $fileCharset)
    {
        ksort($params);
    
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === self::checkEmpty($v) && "@" != substr($v, 0, 1)) {
                // 转换成目标字符集
                $v = self::characet($v, $postCharset, $fileCharset);
                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }
        unset ($k, $v);
        return $stringToBeSigned;
    }
    
    /**
     *  生成 sha256WithRSA 签名
     *
     * @param $content
     * @param $privateKey
     * @param $charset
     * @return
     */
    public static function rsaSign($content, $privateKey, $charset, $signType)
    {
        $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($privateKey, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";
    
            $privateKey = openssl_get_privatekey($privateKey);
            if( ! $privateKey ) {
                return Normal::returnCode(Normal::FAIL,"您使用的私钥格式错误，请检查RSA私钥配置");
            }
    
            //生成签名
            if (self::SIGN_TYPE_RSA2 == $signType) {
                openssl_sign($content, $sign, $privateKey, OPENSSL_ALGO_SHA256);
            } else if (self::SIGN_TYPE_RSA == $signType) {
                openssl_sign($content, $sign, $privateKey);
            } else {
                return Normal::returnCode(Normal::FAIL,"Sign Type is Not Support : signType={$signType}");
            }
    
            openssl_free_key($privateKey);
            $sign = base64_encode($sign);
            return Normal::returnCode(Normal::SUC,"获取private sign成功",[
                'sign'  => $sign
            ]);
    }
    
    /**
     * 检查指定的字符串列表是否不为空。
     */
    public static function areNotEmpty(...$values)
    {
        $result = true;
    
        foreach ($values as $value) {
            $result = !self::checkEmpty($value);
        }
    
        return $result;
    }
    
    
    /**
     * 校验$value是否非空
     *  if not set ,return true;
     *    if is null , return true;
     **/
    public static function checkEmpty($value)
    {
        if (!isset($value)) {
            return true;
        }
        if ($value === null) {
            return true;
        }
        if ( trim($value) === "" ) {
            return true;
        }
        return false;
    }
    
    /**
     * 转换字符集编码
     * @param $data
     * @param $targetCharset
     * @return string
     */
    public static function characet($data, $targetCharset, $fileCharset)
    {
        if (!empty($data)) {
            if (strcasecmp($fileCharset, $targetCharset) != 0) {
                $data = mb_convert_encoding($data, $targetCharset, $fileCharset);
            }
        }
        return $data;
    }
    
    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute( $param = [] )  
    {
        if( empty($this->config['baseurl']) ) {
            return Normal::returnCode(Normal::FAIL,"baseurl不能为空");
        }
        
        if( empty($param['data']) ) {
            return Normal::returnCode(Normal::FAIL,"data不能为空");
        }
        
        if( empty($param['method']) ) {
            return Normal::returnCode(Normal::FAIL,"method不能为空");
        }
        
        $method = $param['method'];
        $data   = $param['data'];
        $url    = $this->config['baseurl'];
        $res    = $this->sign($data,$this->routers[$method]);
        if ( $res['code'] != Normal::SUC){
            return $res;
        }
        $pushData = $res['data'];
        $parameter = [
            [
                'tag'       => 'shopubuy_'.$method,
                'uid'       => IdService::instance()->getOtherID(),
                'url'       => $url,
                'data'      => $pushData,
                'method'    => 'post',
                'format'    => 'x-www-form-urlencoded',
                'header'    => [],
            ],
        ];
        //command情况下，不能使用task关键字
        if( in_array($method,['queryGoodsList','queryGoodsPrice','queryGoodsBrand','queryGoodsClass','queryGoodsStock','queryShopList']) ) {
            $resTask = TaskWorker::instance()->addTask($parameter,'handleDiableTask');
        } else {
            $resTask = TaskWorker::instance()->addTask($parameter);
        }
        
        $resTask    = current($resTask);
        $response   = @json_decode($resTask['response']['result'],true);
        if( isset($response['msg']) && $response['msg'] == 'success' ) {
            return Normal::returnCode(Normal::SUC,"获取成功",$response['content']);
        }
        
        $msg = $response['msg'] ?? '请求失败';
        return Normal::returnCode(Normal::FAIL,$msg,$response);
    }
}